class Promise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onResolvedCallbacks = [];
    this.onRejectedCallbacks = [];
    let resolve = value => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onResolvedCallbacks.forEach(fn => fn());
      }
    };
    let reject = reason => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };
    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }
  then(onFulfilled, onRejected) {
    // 解决 onFufilled，onRejected 没有传值的问题
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err };
    // 每次调用 then 都返回一个新的 promise  Promise/A+ 2.2.7
    let promise2 = new Promise((resolve, reject) => {
      if (this.state === 'fulfilled') {
        setTimeout(() => {
          try {
            resolvePromise(promise2, onFulfilled(this.value), resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      };
      if (this.state === 'rejected') {
        setTimeout(() => {
          try {
            resolvePromise(promise2, onRejected(this.reason), resolve, reject);
          } catch (e) {
            reject(e);
          }
        }, 0);
      };
      if (this.state === 'pending') {
        this.onResolvedCallbacks.push(() => {
          setTimeout(() => {
            try {
              resolvePromise(promise2, onFulfilled(this.value), resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0);
        });
        this.onRejectedCallbacks.push(() => {
          setTimeout(() => {
            try {
              resolvePromise(promise2, onRejected(this.reason), resolve, reject);
            } catch (e) {
              reject(e);
            }
          }, 0)
        });
      };
    });
    return promise2;
  }

  // catch 方法
  catch(onRejected) {
    return this.then(undefined, onRejected);
  }

  static resolve(val) {
    return new Promise((resolve, reject) => {
      resolve(val)
    });
  }

  //添加 reject 方法
  static reject(reason) {
    return new Promise((resolve, reject) => {
      reject(reason);
    });
  }

  //添加 all 方法
  static all(promises) {
    //返回结果为promise对象
    return new Promise((resolve, reject) => {
      //声明变量
      let count = 0;
      let arr = [];
      //遍历
      for (let i = 0; i < promises.length; i++) {
        //
        promises[i].then(
          (v) => {
            //得知对象的状态是成功
            //每个promise对象 都成功
            count++;
            //将当前promise对象成功的结果 存入到数组中
            arr[i] = v;
            //判断
            if (count === promises.length) {
              //修改状态
              resolve(arr);
            }
          },
          (r) => {
            reject(r);
          }
        );
      }
    });
  }

  // 添加 race 方法
  static race(promises) {
    return new Promise((resolve, reject) => {
      for (let i = 0; i < promises.length; i++) {
        promises[i].then(
          (v) => {
            //修改返回对象的状态为 『成功』
            resolve(v);
          },
          (r) => {
            //修改返回对象的状态为 『失败』
            reject(r);
          }
        );
      }
    });
  }
  // 添加 finally 方法
  static finally(onFinished) {
    return this.then((val) => {
      onFinished();

      return val;
    }).catch((err) => {
      onFinished();

      return err;
    });
  }
}
// 解决链式调用和循环引用问题
function resolvePromise(promise2, x, resolve, reject) {
  // 循环引用报错  Promise/A+ 2.3.1
  if (x === promise2) {
    return reject(new TypeError('Chaining cycle detected for promise'));
  }
  let called;
  // x不是null 且x是对象或者函数
  if (x != null && (typeof x === 'object' || typeof x === 'function')) {
    try {
      let then = x.then;
      // 如果then是函数，就默认是promise了
      if (typeof then === 'function') {
        // 就让then执行 第一个参数是this   后面是成功的回调 和 失败的回调
        then.call(x, y => {
          // 成功和失败只能调用一个
          if (called) return;
          called = true;
          resolvePromise(promise2, y, resolve, reject);
        }, err => {
          // 成功和失败只能调用一个
          if (called) return;
          called = true;
          reject(err);
        })
      } else {
        resolve(x);
      }
    } catch (e) {
      // 也属于失败
      if (called) return;
      called = true;
      reject(e);
    }
  } else {
    resolve(x);
  }
}
